/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://github.com/payara/Payara/blob/main/LICENSE.txt
 * See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at legal/OPEN-SOURCE-LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.gjc.spi.base;

import java.util.Arrays;

/**
 *
 * @author Shalini M
 */
public class CacheObjectKey {
    public static final String CALLABLE_STATEMENT = "CS";
    public static final String PREPARED_STATEMENT = "PS";

    protected String sql = null;
    protected String statementType = null;
    protected int resultSetType;
    protected int resultSetConcurrency;
    protected int resultSetHoldability;
    protected int autoGeneratedKeys;
    protected int[] columnIndexes;
    protected String[] columnNames;

    /**
     * Get the value of columnNames
     *
     * @return the value of columnNames
     */
    public String[] getColumnNames() {
        return columnNames;
    }

    /**
     * Set the value of columnNames
     *
     * @param columnNames new value of columnNames
     */
    public void setColumnNames(String[] columnNames) {
        this.columnNames = columnNames;
    }

    /**
     * Get the value of columnIndexes
     *
     * @return the value of columnIndexes
     */
    public int[] getColumnIndexes() {
        return columnIndexes;
    }

    /**
     * Set the value of columnIndexes
     *
     * @param columnIndexes new value of columnIndexes
     */
    public void setColumnIndexes(int[] columnIndexes) {
        this.columnIndexes = columnIndexes;
    }

    public CacheObjectKey(String sql, String statementType, 
            int resultSetType, int resultSetConcurrency) {
        this.sql = sql;
        this.statementType = statementType;
        this.resultSetType = resultSetType;
        this.resultSetConcurrency = resultSetConcurrency;
    }

    public CacheObjectKey(String sql, String statementType,
            int resultSetType, int resultSetConcurrency,
            int resultSetHoldability) {
        this.sql = sql;
        this.statementType = statementType;
        this.resultSetType = resultSetType;
        this.resultSetConcurrency = resultSetConcurrency;
        this.resultSetHoldability = resultSetHoldability;        
    }

    public CacheObjectKey(String sql, String statementType,
            int[] columnIndexes) {
        this.sql = sql;
        this.statementType = statementType;
        this.columnIndexes = columnIndexes;
    }

    public CacheObjectKey(String sql, String statementType,
            String[] columnNames) {
        this.sql = sql;
        this.statementType = statementType;
        this.columnNames = columnNames;
    }
    
    public CacheObjectKey(String sql, String statementType,
            int autoGeneratedKeys) {
        this.sql = sql;
        this.statementType = statementType;
        this.autoGeneratedKeys = autoGeneratedKeys;
    }

    public int getAutoGeneratedKeys() {
        return autoGeneratedKeys;
    }

    public void setAutoGeneratedKeys(int autoGeneratedKeys) {
        this.autoGeneratedKeys = autoGeneratedKeys;
    }

    /**
     * Get the value of resultSetConcurrency
     *
     * @return the value of resultSetConcurrency
     */
    public int getResultSetConcurrency() {
        return resultSetConcurrency;
    }

    /**
     * Set the value of resultSetConcurrency
     *
     * @param resultSetConcurrency new value of resultSetConcurrency
     */
    public void setResultSetConcurrency(int resultSetConcurrency) {
        this.resultSetConcurrency = resultSetConcurrency;
    }

    /**
     * Get the value of resultSetType
     *
     * @return the value of resultSetType
     */
    public int getResultSetType() {
        return resultSetType;
    }

    /**
     * Set the value of resultSetType
     *
     * @param resultSetType new value of resultSetType
     */
    public void setResultSetType(int resultSetType) {
        this.resultSetType = resultSetType;
    }
    /**
     * Get the value of resultSetHoldability
     *
     * @return the value of resultSetHoldability
     */
    public int getResultSetHoldability() {
        return resultSetHoldability;
    }

    /**
     * Set the value of resultSetHoldability
     *
     * @param resultSetHoldability new value of resultSetHoldability
     */
    public void setResultSetHoldability(int resultSetHoldability) {
        this.resultSetHoldability = resultSetHoldability;
    }

    public CacheObjectKey() {
    }

    /**
     * Check for the equality of the CacheObjectKey with the object passed by 
     * 1. comparing the sql string values 
     * 2. comparing the statement type values
     * 3. comapring the getClass() values
     * @param obj obj which is to be checked against this object
     * @return boolean
     */    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final CacheObjectKey other = (CacheObjectKey) obj;
        if (this.sql == null || other.sql == null || !this.sql.equals(other.sql)) {
            return false;
        }
        if (this.statementType == null || other.statementType == null || 
                !this.statementType.equals(other.statementType)) {
            return false;
        }        
        if (this.resultSetType != other.resultSetType) {
            return false;
        }
        if (this.resultSetConcurrency != other.resultSetConcurrency) {
            return false;
        }
        if (this.resultSetHoldability != other.resultSetHoldability) {
            return false;
        }
        if(CacheObjectKey.PREPARED_STATEMENT.equals(other.statementType)) {
            if (this.autoGeneratedKeys != other.autoGeneratedKeys) {
                return false;
            }
            //Iterate through the columnNames/columnIndexes to see if equal
            if(this.columnIndexes != null && other.columnIndexes != null) {
                if (!Arrays.equals(this.columnIndexes, other.columnIndexes)) {
                    return false;
                }
            }
            if(this.columnNames != null && other.columnNames != null) {
                if(!Arrays.equals(this.columnNames, other.columnNames)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Generate hashCode for this object using the sql and statementType fields
     * @return has integer value
     */    
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + (this.sql != null ? this.sql.hashCode() : 0);
        hash = 41 * hash + (this.statementType != null ? this.statementType.hashCode() : 0);
        hash = 41 * hash + this.resultSetType;
        hash = 41 * hash + this.resultSetConcurrency;
        hash = 41 * hash + this.resultSetHoldability;
        if(CacheObjectKey.PREPARED_STATEMENT.equals(this.statementType)) {
            hash = 41 * hash + this.autoGeneratedKeys;
            if(this.columnIndexes != null) {
                for(int i : this.columnIndexes) {
                    hash = 41 * hash + ((Integer) i).hashCode();
                }
            }
            if(this.columnNames != null) {
                for(String str : columnNames) {
                    hash = 41 * hash + str.hashCode();
                }
            }
        }
        return hash;
    }

    /**
     * Get the value of statementType
     *
     * @return the value of statementType
     */
    public String getStatementType() {
        return statementType;
    }

    /**
     * Set the value of statementType
     *
     * @param statementType new value of statementType
     */
    public void setStatementType(String statementType) {
        this.statementType = statementType;
    }

    /**
     * Get the value of sql
     *
     * @return the value of sql
     */
    public String getSql() {
        return sql;
    }

    /**
     * Set the value of sql
     *
     * @param sql new value of sql
     */
    public void setSql(String sql) {
        this.sql = sql;
    }    
}
